package com.bestcem.xm.award.service.impl;


import cn.hutool.core.lang.Dict;
import com.alibaba.fastjson.JSON;
import com.bestcem.bp.grpc.v1.base.Code;
import com.bestcem.bp.pay.grpc.v1.services.ActivityRemain;
import com.bestcem.bp.pay.grpc.v1.services.GetActivityRemainRequest;
import com.bestcem.bp.pay.grpc.v1.services.GetActivityRemainResponse;
import com.bestcem.xm.award.config.FileConfig;
import com.bestcem.xm.award.config.WxConfig;
import com.bestcem.xm.award.constant.Constants;
import com.bestcem.xm.award.constant.RedisKeyConstant;
import com.bestcem.xm.award.dao.AwardAwardDao;
import com.bestcem.xm.award.dao.AwardHistoryDao;
import com.bestcem.xm.award.dao.AwardRedPacketStatsDao;
import com.bestcem.xm.award.dao.AwardRequestDao;
import com.bestcem.xm.award.entity.pojo.*;
import com.bestcem.xm.award.enums.*;
import com.bestcem.xm.award.grpc.client.ActivityGrpcService;
import com.bestcem.xm.award.grpc.client.DeliverGrpcService;
import com.bestcem.xm.award.grpc.service.param.redpacket.WinDetailListParam;
import com.bestcem.xm.award.mq.dto.RedPacketAwardSendingDTO;
import com.bestcem.xm.award.service.DrawCommonService;
import com.bestcem.xm.award.service.RedPacketDisplayService;
import com.bestcem.xm.award.service.WxService;
import com.bestcem.xm.award.service.dto.*;
import com.bestcem.xm.award.service.dto.pay.SendRedPacketResponse;
import com.bestcem.xm.award.service.dto.wx.WxAccessTokenResponse;
import com.bestcem.xm.award.service.mq.send.AwardMessageService;
import com.bestcem.xm.common.core.domain.web.ServiceResult;
import com.bestcem.xm.common.core.oss.enums.OssPathEnum;
import com.bestcem.xm.common.core.uitls.ExcelExportUtil;
import com.bestcem.xm.common.core.uitls.StringUtil;
import com.bestcem.xm.componet.filestorage.service.StorageService;
import com.bestcem.xm.componet.redis.service.RedisService;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.File;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * @author xa.zhan <xa.zhang@idiaoyan.com>
 * @version v1.0
 * @date 2021/6/30 13:55
 * @desc 红包奖励，详情页面数据展示
 */
@Slf4j
@Service
public class RedPacketDisplayServiceImpl implements RedPacketDisplayService {

    private static final int EXPORT_PAGE_SIZE = 10000;
    public static final String ID_ERROR_MSG = "奖励Id参数错误";

    @Resource
    private WxConfig wxConfig;

    /**
     * 默认false,本地测试使用
     */
    @Value("${app.award.devTest:false}")
    private boolean devTest;
    @Resource
    private FileConfig fileConfig;

    @Resource
    private AwardHistoryDao historyDao;
    @Resource
    private AwardAwardDao awardDao;
    @Resource
    private AwardCheck awardCheck;
    @Resource
    private DrawCommonService drawCommonService;
    /*@Resource
    private OssService ossService;*/
    @Resource
    private AwardRequestDao requestDao;
    @Resource
    private WxService wxService;
    @Resource
    private ActivityGrpcService activityGrpcService;
    @Resource
    private DeliverGrpcService deliverGrpcService;
    //    @Resource
//    private RabbitMqMessageSender mqMessageSender;
    @Resource
    private AwardRedPacketStatsDao awardRedPacketStatsDao;
//    @Autowired
//    private RabbitMqConstantConfig rabbitMqConstantConfig;

    @Autowired
    private AwardMessageService awardMessageService;
    @Autowired
    private RedisService redisService;
    @Autowired
    private StorageService storageService;

    /**
     * mock测试使用
     *
     * @return
     */
    public boolean isDebug() {
        return devTest;
    }

    /**
     * 查看红包详情页面中的 获取红包总览
     *
     * @param awardId 奖励id
     * @return 红包总览
     */
    @Override
    public ServiceResult<RedPacketStatsDTO> getRedPacketStats(String awardId) {
        //参数校验
        if (StringUtils.isBlank(awardId)) {
            return ServiceResult.fail("缺少参数");
        }
        AwardAwardDO award = awardDao.findById(awardId);
        if (award == null) {
            return ServiceResult.fail("查找不到奖励记录");
        }
        if (!StringUtil.checkObjectId(awardId)) {
            return ServiceResult.fail(ID_ERROR_MSG);
        }

        //奖励设置信息校验
        AwardAwardDO.Basic basic = award.getBasic();
        if (basic == null) {
            return ServiceResult.fail("查找不到奖励设置信息");
        }
        Integer total = basic.getTotalCount();

        BigDecimal totalAmount = basic.getTotalAmount();

        //计算总金额
        //totalAmount可能为""
        if (totalAmount == null && total != null) {
            BigDecimal totalBig = new BigDecimal(total.intValue());
            //小数、整数、""
            BigDecimal sinAmount = basic.getSinAmount();
            if (sinAmount != null) {
                totalAmount = totalBig.multiply(sinAmount);
            }
        }

        RedPacketStatsCacheDO redPacketStatsCacheDO = awardRedPacketStatsDao.selectByAwardId(awardId);
        RedPacketStatsDTO bonusOverviewDto = new RedPacketStatsDTO();

        if (redPacketStatsCacheDO == null) {
            //统计数据
            RedPacketStatsDO redPacketStatsDO = historyDao.getSendAmountAndCount(awardId);
            if (redPacketStatsDO != null) {
                BeanUtils.copyProperties(redPacketStatsDO, bonusOverviewDto);
                long amount = redPacketStatsDO.getSentAmount().multiply(BigDecimal.valueOf(Constants.LONG_HUNDRED)).longValue();
                awardRedPacketStatsDao.insert(awardId, redPacketStatsDO.getSentCount(), amount);
            } else {
                awardRedPacketStatsDao.insert(awardId, Constants.ZERO, Constants.ZERO);
            }

        } else {
            bonusOverviewDto.setSentAmount(BigDecimal.valueOf(redPacketStatsCacheDO.getAmount()).divide(BigDecimal.valueOf(Constants.LONG_HUNDRED)).setScale(2));
            bonusOverviewDto.setSentCount(redPacketStatsCacheDO.getCount().intValue());
        }


        //组合数据，设置默认值，
        setRedPacketStatsInfo(bonusOverviewDto, totalAmount, total);

        return ServiceResult.success(bonusOverviewDto);
    }

    /**
     * 组合数据，设置默认值
     *
     * @param bonusOverviewDto
     * @param totalAmount
     * @param total
     */
    private void setRedPacketStatsInfo(RedPacketStatsDTO bonusOverviewDto, BigDecimal totalAmount, Integer total) {
        if (bonusOverviewDto == null) {
            return;
        }
        if (bonusOverviewDto.getSentCount() == null) {
            bonusOverviewDto.setSentCount(0);
        }
        if (bonusOverviewDto.getSentAmount() == null) {
            bonusOverviewDto.setSentAmount(BigDecimal.ZERO);
        }

        if (totalAmount == null) {
            totalAmount = BigDecimal.ZERO;
        }
        bonusOverviewDto.setTotalAmount(totalAmount);
        bonusOverviewDto.setTotalCount(total == null ? 0 : total);
        bonusOverviewDto.setWaitCount(total - bonusOverviewDto.getSentCount());
        bonusOverviewDto.setWaitAmount(totalAmount.subtract(bonusOverviewDto.getSentAmount()));
    }

    /**
     * 查看红包详情页面中的中奖名单 获取中奖人数
     *
     * @param awardId 奖励id
     * @return 中奖人数
     */
    @Override
    public ServiceResult<Integer> getWinCount(String awardId) {
        if (!StringUtil.checkObjectId(awardId)) {
            return ServiceResult.fail(ID_ERROR_MSG);
        }

        long count = historyDao.getWinCount(awardId);

        return ServiceResult.success(Long.valueOf(count).intValue());
    }

    /**
     * 查看红包详情页面中的 获取投放数据统计
     *
     * @param awardId 奖励id
     * @return 投放数据统计
     */
    @Override
    public ServiceResult<List<DeliverDetailDTO>> getDeliverDetail(String awardId) {
        if (!StringUtil.checkObjectId(awardId)) {
            return ServiceResult.fail(ID_ERROR_MSG);
        }

        List<DeliverDetailDO> doList = historyDao.getDeliverDetail(awardId);
        if (doList == null) {
            doList = new ArrayList<>();
        }

        List<DeliverDetailDTO> list = new ArrayList<>();
        for (DeliverDetailDO deliverDetailDO : doList) {
            DeliverDetailDTO deliverDetailDTO = new DeliverDetailDTO();
            BeanUtils.copyProperties(deliverDetailDO, deliverDetailDTO);
            list.add(deliverDetailDTO);
        }

        return ServiceResult.success(list);
    }

    /**
     * 查看红包详情页面中的中奖名单 投放名称列表获取
     *
     * @param awardId 奖励id
     * @return 投放名称列表
     */
    @Override
    public ServiceResult<List<String>> getDeliverNameList(String awardId) {
        if (!StringUtil.checkObjectId(awardId)) {
            return ServiceResult.fail(ID_ERROR_MSG);
        }

        List<String> list = historyDao.getDeliverNameList(awardId);
        if (list == null) {
            list = new ArrayList<>();
        }

        return ServiceResult.success(list);
    }


    /**
     * 查看红包详情页面中的中奖名单 中奖名单列表
     *
     * @param param 请求参数
     * @return 中奖名单列表
     */
    @Override
    public ServiceResult<WinDetailDTO> getWinDetailList(WinDetailListParam param) {

        if (StringUtils.isBlank(param.getAwardId()) || !StringUtil.checkObjectId(param.getAwardId())) {
            return ServiceResult.fail(ID_ERROR_MSG);
        }
        if (param.getPage() == null) {
            param.setPage(1);
        }
        if (param.getSize() == null) {
            param.setSize(10);
        }
        WinDetailDTO winDetailDto = new WinDetailDTO();
        long count = historyDao.getWinDetailListCount(param);
        List<AwardHistoryDO> historyList = historyDao.getWinDetailList(param);
        List<WinDetailRowDTO> detailRowDtoList = new ArrayList<>();
        historyList.stream().forEach(history -> {
            WinDetailRowDTO detailRowDto = new WinDetailRowDTO();
            BeanUtils.copyProperties(history, detailRowDto);
            detailRowDtoList.add(detailRowDto);
        });
        winDetailDto.setTotal(Long.valueOf(count).intValue());
        winDetailDto.setList(detailRowDtoList);

        return ServiceResult.success(winDetailDto);
    }

    /**
     * 查看红包详情页面中的中奖名单 中奖名单列表
     *
     * @param param 请求参数
     * @return oss url信息
     */
    @Override
    public ServiceResult<FileInfoDTO> exportWinDetailList(WinDetailListParam param) {
        if (StringUtils.isBlank(param.getAwardId()) || !StringUtil.checkObjectId(param.getAwardId())) {
            return ServiceResult.fail(ID_ERROR_MSG);
        }

        AwardAwardDO award = awardDao.findById(param.getAwardId());
        if (Objects.isNull(award)) {
            return ServiceResult.fail("奖励不存在");
        }

        param.setPage(1);
        param.setSize(EXPORT_PAGE_SIZE);

        List<WinDetailRowDTO> allList = new ArrayList<>();

        long total = historyDao.getWinDetailListCount(param);
        int allPage = (int) (total / EXPORT_PAGE_SIZE + 1);

        //分页查询
        for (int curPage = 1; curPage <= allPage; curPage++) {
            param.setPage(curPage);
            List<AwardHistoryDO> historyList = historyDao.getWinDetailList(param);
            List<WinDetailRowDTO> detailRowDtoList = new ArrayList<>();
            historyList.stream().forEach(history -> {
                WinDetailRowDTO detailRowDto = new WinDetailRowDTO();
                BeanUtils.copyProperties(history, detailRowDto);
                detailRowDtoList.add(detailRowDto);
            });
            allList.addAll(detailRowDtoList);
        }

        //数据转换
        List<WinDetailExportDTO> exportDataList = new ArrayList<>();
        for (WinDetailRowDTO detailRowDto : allList) {
            exportDataList.add(WinDetailExportDTO.createExcelData(detailRowDto));
        }
        allList.clear();

        //开始导出
        String awardName = award.getName();
        String date = new SimpleDateFormat("yyyyMMdd").format(new Date());
        String fileName = awardName + "_中奖名单_" + date + ".xlsx";
        File excelFile = ExcelExportUtil.createExcelStream(exportDataList, WinDetailExportDTO.class, fileConfig.getTempFilePath());
        //String url = ossService.uploadTempFile(excelFile, fileName, OssPathEnum.TEMP_AWARD, Constants.OSS_TEMP_EXPIRE_SECOND, null, "红包中奖明细导出");
        String url = storageService.upload(excelFile, fileName, OssPathEnum.TEMP_AWARD.getPath(), new Dict()).getUrl();
        if (Objects.nonNull(excelFile)) {
            excelFile.delete();
        }
        return ServiceResult.success(new FileInfoDTO("", fileName, url));
    }


    /**
     * 红包领取前置校验，是否可领取红包
     *
     * @param awardId 奖励id
     * @param code    用户授权code
     * @return 返回requestId等信息
     */
    @Override
    public ServiceResult<RedPacketEntryDTO> getRedPacketDraw(String awardId, String code, String requestId) {

        if (StringUtils.isBlank(code)) {
            return ServiceResult.fail(AwardErrorMsgEnum.CUSTOM_ERROR.getResponseMsg("缺少必填参数code"));
        }
        // 查询openId
        String openId = getOpenId(code);
        if (wxConfig.isTest()) {
            openId = "5ec7442015377614c48f43d1";
        }
        if (openId == null) {
            return ServiceResult.fail(AwardErrorMsgEnum.AWARD_NO_OPENID.getResponseMsg());
        }
        //查询激活中的奖励
        AwardAwardDO award = awardDao.findByAwardIdAndStatus(awardId, AwardStatusEnum.ACTIVE.getIndex());
        if (award == null) {
            return ServiceResult.fail(AwardErrorMsgEnum.AWARD_STOPPED.getResponseMsg());
        }
        //检查单个帐号领取次数限制
        if (!checkAccountLimit(award, openId)) {
            return ServiceResult.fail(AwardErrorMsgEnum.AWARD_ACCOUNT_LIMIT.getResponseMsg());
        }
        //判断 request表数据状态 是等待抽奖的状态
        AwardRequestDO awardRequestDO = requestDao.findAndModify(requestId, AwardRequestStatusEnum.PASS, awardId, AwardRequestStatusEnum.SEQ);
        if (awardRequestDO == null) {
            return ServiceResult.fail(AwardErrorMsgEnum.CUSTOM_ERROR.getResponseMsg("request not found"));
        }

        String deliverId = String.valueOf(awardRequestDO.getDeliver().get("deliver_id"));
        //查找信息，填充到history
        DeliverRpcDTO deliver = null;
        if (isDebug()) {
            deliver = new DeliverRpcDTO();
            deliver.setChannel(DeliverSourceEnum.QRCODE.getIndex());
            deliver.setName("test deliever name");
        } else {
            deliver = deliverGrpcService.getDeliverDto(deliverId);
        }
        if (deliver == null) {
            return ServiceResult.fail(AwardErrorMsgEnum.CUSTOM_ERROR.getResponseMsg("deliver not found"));
        }

        //根据 awardid、deliverId、requestID查询hsitory,更新openId,deliverName、deliverChannel、seq
        AwardHistoryDO history = historyDao.findByRequest(awardId, deliverId, requestId);
        if (history != null && history.getStatus().intValue() != RedPacketStatusEnum.PASS.getIndex()) {
            return ServiceResult.fail(AwardErrorMsgEnum.AWARD_ACCOUNT_LIMIT.getResponseMsg());
        }

        AwardHistoryDO awardHistoryDO = new AwardHistoryDO();
        awardHistoryDO.setHistoryId(StringUtil.getId());
        awardHistoryDO.setAwardId(awardId);
        awardHistoryDO.setDeliverId(deliverId);
        awardHistoryDO.setRequestId(requestId);
        awardHistoryDO.setOpenId(openId);
        awardHistoryDO.setDeliverName(deliver.getName());
        awardHistoryDO.setDeliverChannel(deliver.getChannel());

        awardHistoryDO.setSeq(Long.valueOf(awardRequestDO.getSurvey().getSeq()));
        awardHistoryDO.setStatus(RedPacketStatusEnum.PASS.getIndex());
        historyDao.insertSelective(awardHistoryDO);

        RedPacketEntryDTO redPacketEntryDto = new RedPacketEntryDTO();
        redPacketEntryDto.setRequestId(requestId);
        redPacketEntryDto.setAwardId(awardId);

        if (award.getBasic() != null) {
            redPacketEntryDto.setDisplayLogoId(award.getBasic().getDisplayLogoId());
            redPacketEntryDto.setDisplayLogoPath(award.getBasic().getDisplayLogoPath());
            redPacketEntryDto.setDisplayName(award.getBasic().getDisplayName());
        }

        return ServiceResult.success(redPacketEntryDto);
    }

    /**
     * 领取红包
     *
     * @param requestId request表的id
     * @param awardId   award表的id
     * @return 红包金额
     */
    @Override
    public ServiceResult<Integer> drawRedPacket(String requestId, String awardId) {

        AwardAwardDO award = awardDao.findByAwardIdAndStatus(awardId, AwardStatusEnum.ACTIVE.getIndex());
        //参数校验，状态校验
        AwardHistoryDO history = historyDao.findOneByAwardIdAndRequestIdAndStatus(awardId, requestId, RedPacketStatusEnum.PASS.getIndex());

        //前置检查，判断是否中奖
        ServiceResult preCheckResult = preCheck(award, history);
        //未中奖
        if (!preCheckResult.isSuccess()) {
            return preCheckResult;
        }

        Integer probability = (Integer) preCheckResult.getData();
        //python特殊处理,实际与seq相同
        String orderId = history.getSeq().toString();
        String basicName = "";
        if (award.getBasic() != null && award.getBasic().getName() != null) {
            basicName = award.getBasic().getName();
        }

        //调用钱包发送红包
        SendRedPacketResponse sendRedPacketResult = null;
        //用来保存LuckMoneyStatusEnum index
        RedPacketStatusEnum redPacketStatusEnum = null;
        if (isDebug()) {
            sendRedPacketResult = new SendRedPacketResponse();
            sendRedPacketResult.setStatus(PayLuckMoneyStatusEnum.SENT.getIndex());
            sendRedPacketResult.setAmount(300);
        } else {
            sendRedPacketResult = activityGrpcService.pickMoney(award.getActivityId(), orderId, history.getOpenId(), basicName, 0);
        }
        if (log.isInfoEnabled()) {
            log.info("activityGrpcService.pickMoney result:{}", JSON.toJSONString(sendRedPacketResult));
        }
        //概率红包发放失败后，重新放回奖池
        if (sendRedPacketResult == null || sendRedPacketResult.getStatus() == null
                || sendRedPacketResult.getStatus().intValue() == PayLuckMoneyStatusEnum.FAILURE.getIndex()) {
            //钱包发送红包失败后，奖品返还到奖池
            returnToPool(probability, awardId, requestId);

            AwardHistoryDO updateEntity = new AwardHistoryDO();
            updateEntity.setStatus(RedPacketStatusEnum.FAIL.getIndex());
            updateEntity.setHistoryId(history.getHistoryId());
            historyDao.updateByPrimaryKeySelective(updateEntity);
            return ServiceResult.fail(AwardErrorMsgEnum.CUSTOM_ERROR.getResponseMsg("红包发送失败"));
        } else if (sendRedPacketResult.getStatus().intValue() == PayLuckMoneyStatusEnum.SENDING.getIndex()) {
            redPacketStatusEnum = RedPacketStatusEnum.SENDING;
            //发送中状态，等60秒，重新查询
            //红包发送状态mq
            RedPacketAwardSendingDTO redPacketAwardSendingDTO = new RedPacketAwardSendingDTO();
            redPacketAwardSendingDTO.setAwardId(awardId);
            redPacketAwardSendingDTO.setActivityId(award.getActivityId());
            redPacketAwardSendingDTO.setOrderId(orderId);
//            try {
//                mqMessageSender.sendDelayMsg(rabbitMqConstantConfig.getAppBpAwardDelayExchange(), rabbitMqConstantConfig.getAppBpAwardDelayRoutingKey(), AwardMqConstant.RED_PACKET_SENDING_TOPIC, redPacketAwardSendingDTO, 60 * 1000);
//            } catch (JsonProcessingException e) {
//                log.error(String.format("发送检查红包发送状态mq消息失败%s,%s,%s", awardId, award.getActivityId(), orderId), e);
//            }
            awardMessageService.awardRedPacketSendingSend(redPacketAwardSendingDTO, 60 * 1000);

            if (log.isInfoEnabled()) {
                log.info("中台接口返回红包状态发送中, 待更新状态, award_id={}, order_id={}", awardId, orderId);
            }
        } else if (sendRedPacketResult.getStatus().intValue() == PayLuckMoneyStatusEnum.SENT.getIndex()) {
            redPacketStatusEnum = RedPacketStatusEnum.SENT;
            //已发送
            drawCommonService.updateAwardAndSendNotification(awardId);
            awardRedPacketStatsDao.addCountAndAmountByAwardId(awardId, Constants.INT1, sendRedPacketResult.getAmount() == null ? 0 : sendRedPacketResult.getAmount());
        } else {
            redPacketStatusEnum = RedPacketStatusEnum.FAIL;
        }


        Integer amount = sendRedPacketResult.getAmount() == null ? 0 : sendRedPacketResult.getAmount();

        AwardHistoryDO updateEntity = new AwardHistoryDO();
        updateEntity.setHistoryId(history.getHistoryId());
        updateEntity.setOrderId(orderId);
        updateEntity.setAmount(amount);
        updateEntity.setStatus(redPacketStatusEnum.getIndex());
        updateEntity.setSendTime(com.bestcem.xm.common.core.uitls.DateUtil.getCommonDate());
        historyDao.updateByPrimaryKeySelective(updateEntity);

        return ServiceResult.success(amount);
    }

    /**
     * 钱包发送红包失败后，奖品返还到奖池
     */
    private void returnToPool(Integer probability, String awardId, String requestId) {
        if (probability != 0) {
            String lockKey = String.format(RedisKeyConstant.RED_PACKET_LOCK, awardId);
            redisService.lock(lockKey);
            try {
                redisService.lRightPush(String.format(RedisKeyConstant.AWARD_POOL, awardId), Constants.ONE_STRING);
                if (log.isInfoEnabled()) {
                    log.info("prob bonus [request_id={} send failed, already put back to redis pool", requestId);
                }
            } finally {
                redisService.unlock(lockKey);
            }
        }
    }

    /**
     * 前置检查是否中奖
     *
     * @param award   奖励
     * @param history 奖励历史记录
     * @return 结果
     */
    private ServiceResult preCheck(AwardAwardDO award, AwardHistoryDO history) {
        if (award == null) {
            return ServiceResult.fail(AwardErrorMsgEnum.AWARD_STOPPED.getResponseMsg());
        }
        if (history == null) {
            return ServiceResult.fail(AwardErrorMsgEnum.BONUS_UNLUCKY.getResponseMsg());
        }
        String openId = history.getOpenId();
        if (StringUtils.isBlank(openId)) {
            return ServiceResult.fail(AwardErrorMsgEnum.CUSTOM_ERROR.getResponseMsg("openid not exists"));
        }
        //检查单个帐号领取次数限制
        if (!checkAccountLimit(award, openId)) {
            return ServiceResult.fail(AwardErrorMsgEnum.AWARD_ACCOUNT_LIMIT.getResponseMsg());
        }

        //中奖概率
        int probability = 0;
        if (award.getBasic() != null && award.getBasic().getProbability() != null) {
            probability = award.getBasic().getProbability().intValue();
        } else {
            probability = -1;
        }

        //百分百中奖
        if (probability == 0) {
            //不通过,红包领取完毕
            if (!checkAwardEmpty(award.getActivityId())) {
                AwardHistoryDO updateEntity = new AwardHistoryDO();
                updateEntity.setStatus(RedPacketStatusEnum.TOTAL.getIndex());
                updateEntity.setHistoryId(history.getHistoryId());
                historyDao.updateByPrimaryKeySelective(updateEntity);
                return ServiceResult.fail(AwardErrorMsgEnum.AWARD_EMPTY.getResponseMsg());
            }
        }
        //概率红包
        else if (probability > 0) {
            // 检查参与人数是否到达预计人数
            if (!awardCheck.checkReachable(award.getId())) {
                AwardHistoryDO updateEntity = new AwardHistoryDO();
                updateEntity.setStatus(RedPacketStatusEnum.TOTAL.getIndex());
                updateEntity.setHistoryId(history.getHistoryId());
                historyDao.updateByPrimaryKeySelective(updateEntity);
                return ServiceResult.fail(AwardErrorMsgEnum.BONUS_UNLUCKY.getResponseMsg());
            }

            //概率红包尝试开始抽奖,如果未抽中
            if (!draw(award.getId())) {
                AwardHistoryDO updateEntity = new AwardHistoryDO();
                updateEntity.setStatus(RedPacketStatusEnum.NOWIN.getIndex());
                updateEntity.setHistoryId(history.getHistoryId());
                historyDao.updateByPrimaryKeySelective(updateEntity);

                return ServiceResult.fail(AwardErrorMsgEnum.BONUS_UNLUCKY.getResponseMsg());
            }
        } else {
            return ServiceResult.fail(AwardErrorMsgEnum.AWARD_INACTIVE.getResponseMsg());
        }
        //检查日限额
        if (!checkDayLimit(award)) {
            AwardHistoryDO updateEntity = new AwardHistoryDO();
            updateEntity.setStatus(RedPacketStatusEnum.DAY.getIndex());
            updateEntity.setHistoryId(history.getHistoryId());
            updateEntity.setSendTime(new Date());
            historyDao.updateByPrimaryKeySelective(updateEntity);
            return ServiceResult.fail(AwardErrorMsgEnum.AWARD_DAY_LIMIT.getResponseMsg());
        }
        return ServiceResult.success(Integer.valueOf(probability));
    }

    /**
     * 检查是否达到当日领取上限, 通过True， 不通过False
     *
     * @return
     */
    private boolean checkDayLimit(AwardAwardDO award) {
        if (award != null && award.getRule() != null && award.getRule().getDay() != null) {
            long count = historyDao.countByIdAndStatus(award.getId(),
                    Lists.newArrayList(RedPacketStatusEnum.SENT.getIndex(), RedPacketStatusEnum.SENDING.getIndex()));
            if (count >= award.getRule().getDay()) {
                return false;
            }
        }
        return true;
    }

    /**
     * 概率红包尝试开始抽奖
     *
     * @param awardId
     * @return
     */
    public boolean draw(String awardId) {
        boolean flag = false;
        //等待获取锁
        redisService.lock(String.format(RedisKeyConstant.RED_PACKET_LOCK, awardId));
        try {
            String value = redisService.lRightPop(String.format(RedisKeyConstant.AWARD_POOL, awardId));
            //中奖
            if (Constants.ONE_STRING.equals(value)) {
                flag = true;
            }
        } catch (Exception e) {
            flag = false;
            log.error("领取概率红包失败", e);
        } finally {
            //释放锁
            redisService.unlock(String.format(RedisKeyConstant.RED_PACKET_LOCK, awardId));
        }

        if (isDebug()) {
            return true;
        }

        return flag;
    }

    /**
     * check_empty调用钱包查询 检查红包是否领取完毕, 从红包中台接口获取，通过True， 不通过False
     *
     * @param activityId 活动id
     * @return 通过True， 不通过False
     */
    private boolean checkAwardEmpty(String activityId) {

        if (isDebug()) {
            return true;
        }

        //check_empty调用钱包查询 检查红包是否领取完毕, 从红包中台接口获取，通过True， 不通过False
        GetActivityRemainRequest request = GetActivityRemainRequest.newBuilder().setId(activityId).build();
        GetActivityRemainResponse activityRemain = activityGrpcService.getActivityRemain(request);

        if (activityRemain.getStatus().getCodeValue() != Code.OK_VALUE) {
            return false;
        }
        ActivityRemain remain = activityRemain.getRemain();

        if (remain != null && remain.getAmount() > 0 && remain.getNum() > 0) {
            return true;
        }

        return false;
    }

    /**
     * 红包领取时，单个帐号领取次数限制
     *
     * @param award
     * @param openId
     * @return
     */
    boolean checkAccountLimit(AwardAwardDO award, String openId) {
        //红包单个帐号领取次数限制
        AwardAwardDO.Rule rule = award.getRule();
        if (rule != null && rule.getWin() != null) {
            long count = historyDao.countByIdAndOpenIdAndNotPass(award.getId(), openId);
            if (count >= rule.getWin()) {
                return false;
            }
        }

        return true;
    }

    /**
     * 根据code获取用户openId
     *
     * @param code 用户授权后返回的code
     * @return
     */
    private String getOpenId(String code) {
        WxAccessTokenResponse wxAccessTokenResponse = wxService.requestAccessToken(code);
        if (wxAccessTokenResponse != null) {
            return wxAccessTokenResponse.getOpenid();
        }
        return null;
    }
}